#include "CRender.h"
#include "gltools.h"
#include <algorithm>

CRender *CRender::GetInstance()
{
	static CRender Instance;
	return &Instance;
}

void CRender::InitOpenGL()
{
	glClearColor(0.0f, 0.5f, 0.9f, 1.0f);
	glLineWidth(3);
	glDisable(GL_CULL_FACE);
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glPointSize(4);

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	memset(m_handleShader, 0, sizeof(unsigned int)*eSHADER_MAX);
	LoadShaders("TexVertShader.nick", "TexFragShader.nick", eSHADER_TEXTURE);
	LoadShaders("DeformVertShader.nick", "DeformFragShader.nick", eSHADER_TEXTURE);
}

void CRender::Resize(int nWidth, int nHeight)
{
	glViewport(0, 0, nWidth, nHeight);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	// This is for a 2d projection
	//gluOrtho2D(0, nWidth, nHeight, 0);
	GLdouble xmin, xmax, ymin, ymax;

   ymax = 0.1f * tan(45 * 3.14159f / 360.0);
   ymin = -ymax;
   xmin = ymin * 1;
   xmax = ymax * 1;


   glFrustum(xmin, xmax, ymin, ymax, 0.1f, 1000.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void CRender::Shutdown()
{
	CTextureManager::GetInstance()->ReleaseAll();
}

void CRender::Render()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	SortDrawList();

// 	glEnable(GL_STENCIL_TEST);
// 	glClear(GL_STENCIL_BUFFER_BIT);
// 	glClearStencil(0);
// 	glStencilFunc(GL_NEVER, 0x0, 0x0);
// 	glStencilOp(GL_INCR, GL_INCR, GL_INCR);
// 
  	glEnable(GL_TEXTURE_2D);
// 	for (unsigned int i = 0; i < m_vDrawList.size(); i++)
// 	{
// 		if(m_vDrawList[i].pTex)
// 		{
// 			glPushMatrix();
// 			glBindTexture(GL_TEXTURE_2D, m_vDrawList[i].pTex->m_unHandle);
// 			glColor3f(1, 1, 1);
// 			glTranslatef(m_vDrawList[i].Pos.x, m_vDrawList[i].Pos.y, 0);
// 			if (m_vDrawList[i].bFlipped)
// 			{
// 				glRotatef(180, 0, 1, 0);
// 				//if (m_vDrawList[i].Pos.x > 0)
// 				//m_vDrawList[i].fRot = -m_vDrawList[i].fRot;
// 			}
// 			else if (m_vDrawList[i].Pos.x > 0)
// 			{
// 				//m_vDrawList[i].fRot = -m_vDrawList[i].fRot;
// 			}
// 			glRotatef(m_vDrawList[i].fRot, 0, 0, 1);
// 
// 			glVertexPointer(2, GL_FLOAT, 0, m_vDrawList[i].pShape->GetVertexDataPointer());
// 			glTexCoordPointer(2, GL_FLOAT, 0, m_vDrawList[i].pShape->GetTextureCoordPointer());
// 			glDrawArrays(GL_TRIANGLE_STRIP, 0, m_vDrawList[i].pShape->m_numberVerts);
// 
// 			glPopMatrix();
// 		}
// 	}
// 
// 	glStencilFunc(GL_LESS, 0x0, 0xff);
// 	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

	for (unsigned int i = 0; i < m_vDrawList.size(); i++)
	{
		if(m_vDrawList[i].pTex)
		{
			glPushMatrix();
			glBindTexture(GL_TEXTURE_2D, m_vDrawList[i].pTex->m_unHandle);
			glColor4f(1, 1, 1, m_vDrawList[i].fAlpha);
			if (!m_vDrawList[i].bNoTransform)
			{
				glTranslatef(m_vDrawList[i].Pos.x, m_vDrawList[i].Pos.y, 0);
				if (m_vDrawList[i].bFlipped)
				{
					glRotatef(180, 0, 1, 0);
					//if (m_vDrawList[i].Pos.x > 0)
					//m_vDrawList[i].fRot = -m_vDrawList[i].fRot;
				}
				else if (m_vDrawList[i].Pos.x > 0)
				{
					//m_vDrawList[i].fRot = -m_vDrawList[i].fRot;
				}
				glRotatef(m_vDrawList[i].fRot, 0, 0, 1);
			}
			else
			{
				//Rotate enough to undo the camera
				glRotatef(-m_fUndoTheta / 3.14159f * 180, 0, 0, 1);
			}
			glVertexPointer(2, GL_FLOAT, 0, m_vDrawList[i].pShape->GetVertexDataPointer());
			glTexCoordPointer(2, GL_FLOAT, 0, m_vDrawList[i].pShape->GetTextureCoordPointer());
			glDrawArrays(GL_TRIANGLE_STRIP, 0, m_vDrawList[i].pShape->m_numberVerts);

			glPopMatrix();
		}
	}

	glStencilFunc(GL_LESS, 0x0, 0xff);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

	for (unsigned int i = 0; i < m_vDrawList.size(); i++)
	{
		if(m_vDrawList[i].pTex)
		{
			glPushMatrix();
			glBindTexture(GL_TEXTURE_2D, m_vDrawList[i].pTex->m_unHandle);
			glColor4f(1, 1, 1, m_vDrawList[i].fAlpha);
			if (m_vDrawList[i].bNoTransform)
			{
				glLoadIdentity();
				glTranslatef(0, 0, -40);
				//glRotatef(m_fUndoTheta / 3.14159f * 180, 0, 0, 1);
			}
			else
			{
				glTranslatef(m_vDrawList[i].Pos.x, m_vDrawList[i].Pos.y, 0);
				if (m_vDrawList[i].bFlipped)
				{
					glRotatef(180, 0, 1, 0);
					//if (m_vDrawList[i].Pos.x > 0)
					m_vDrawList[i].fRot = -m_vDrawList[i].fRot;
				}
				else if (m_vDrawList[i].Pos.x > 0)
				{
					//m_vDrawList[i].fRot = -m_vDrawList[i].fRot;
				}
				glRotatef(m_vDrawList[i].fRot, 0, 0, 1);
			}

			glVertexPointer(2, GL_FLOAT, 0, m_vDrawList[i].pShape->GetVertexDataPointer());
			glTexCoordPointer(2, GL_FLOAT, 0, m_vDrawList[i].pShape->GetTextureCoordPointer());
			glDrawArrays(GL_TRIANGLE_STRIP, 0, m_vDrawList[i].pShape->m_numberVerts);
			glPopMatrix();
		}
	}
	glDisable(GL_TEXTURE_2D);

	m_vDrawList.clear();
}


void CRender::DrawTex(Texture *pTex, CShape *pShape, Vec2 Pos, float fZ, float fRot, bool bFlipped, SHADER_TYPE shaderType, float fAlpha, bool bNoTrans)

{
	Drawable Draw;
	Draw.pTex = pTex;
	Draw.pShape = pShape;
	Draw.Pos = Pos;
	Draw.fZ = fZ;
	Draw.fRot = fRot * 180 / 3.14159f;
	Draw.bFlipped = bFlipped;
	Draw.shaderHandle = shaderType;
	Draw.fAlpha = fAlpha;
	Draw.bNoTransform = bNoTrans;
	m_vDrawList.push_back(Draw);
}

void CRender::SortDrawList()
{
	sort(m_vDrawList.begin(), m_vDrawList.end());
}

bool CRender::LoadShaders(char* szVertexFileName, char* szPixelFileName, SHADER_TYPE shaderToLoad)
{
	m_handleShader[shaderToLoad] = gltLoadShaderPairWithAttributes(szVertexFileName, szPixelFileName, 2,
																	GLT_ATTRIBUTE_VERTEX, "vVertex",
																	GLT_ATTRIBUTE_TEXTURE0, "vTexCoord");
	return true;
	
	//Just in case.
	return true;
}